package ro.gillardon.beans;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

import org.apache.log4j.Logger;

import ro.gillardon.business.exception.BusinessException;
import ro.gillardon.business.priceservice.HotelPriceService;
import ro.gillardon.business.priceservice.impl.hotel.HotelPriceServiceEJB;
import ro.gillardon.commons.dto.HotelDTO;
import ro.gillardon.commons.dto.HotelOfferDTO;
import ro.gillardon.commons.enums.City;
import ro.gillardon.commons.enums.Hotel;
import ro.gillardon.commons.enums.RoomType;
import ro.gillardon.commons.hotel.HotelConditions;
import ro.gillardon.commons.hotel.HotelDetailsWrapper;
import ro.gillardon.commons.hotel.HotelOfferDetails;
import ro.gillardon.commons.logger.BTPLogger;
import ro.gillardon.commons.util.DateUtils;

@ManagedBean(name = "dropdownViewHotels", eager = true)
@SessionScoped
public class HotelView {

  private static final Logger LOG = Logger.getLogger(HotelView.class);
  private List<Hotel> hotels;
  private List<City> locations;
  private List<HotelOfferDTO> details;
  private List<RoomType> roomTypes;
  private HotelDTO hotel;
  private double price;

  @EJB
  private final HotelPriceService hotelEJB =
  (HotelPriceService) BeanProvider.getEJB(HotelPriceServiceEJB.class.getSimpleName());

  public HotelView() {
    //this constructor is empty on purpose
  }

  @PostConstruct
  public void init() {
    this.locations = new ArrayList<City>();
    this.details = new ArrayList<HotelOfferDTO>();
    this.hotel = new HotelDTO();
    this.hotels = new ArrayList<Hotel>();
    this.roomTypes = new ArrayList<RoomType>();
    this.roomTypes.add(RoomType.SINGLE);
    this.roomTypes.add(RoomType.DOUBLE);
  }

  public void onLocationChange() {
    try {
      if (this.hotel.getLocation() == null && "".equals(this.hotel.getLocation())) {
        this.hotels = new ArrayList<Hotel>();
      } else {
        this.hotels = this.hotelEJB.getHotelsForLocation(City.valueOf(this.hotel.getLocation()));
      }
    } catch (BusinessException e) {
      BTPLogger.error(LOG, e);
    }
  }

  private double getOfferWeekdayPrice(final HotelDetailsWrapper hdw, final RoomType r) {
    if ("SINGLE".equals(r.toString())) {
      return hdw.getSingleRoomWeekdayPrice().getAmount();
    } else {
      return hdw.getDoubleRoomWeekdayPrice().getAmount();
    }
  }

  private double getOfferWeekendPrice(final HotelDetailsWrapper hdw, final RoomType r) {
    if ("SINGLE".equals(r.toString())) {
      return hdw.getSingleRoomWeekendPrice().getAmount();
    } else {
      return hdw.getDoubleRoomWeekendPrice().getAmount();
    }
  }

  public void changePrice() {
    if (this.hotel.getLocation() != null &&
      !"".equals(this.hotel.getLocation()) &&
      this.hotel.getName() != null &&
      !"".equals(this.hotel.getName()) &&
      this.hotel.getRoomType() != null &&
      !"".equals(this.hotel.getRoomType())) {

      try {
        HotelDetailsWrapper hwd = this.hotelEJB.getOffers(new HotelConditions(Hotel.valueOf(this.hotel.getName())));
        this.price = getHotelDTOPrice(getOfferWeekdayPrice(hwd, RoomType.valueOf(this.hotel.getRoomType())),
          getOfferWeekendPrice(hwd, RoomType.valueOf(this.hotel.getRoomType())));
      } catch (BusinessException e) {
        BTPLogger.error(LOG, e);
      }
    }

  }

  public void changeMessage() {
    if (this.hotel.getLocation() != null &&
      !"".equals(this.hotel.getLocation()) &&
      this.hotel.getName() != null &&
      !"".equals(this.hotel.getName())) {

      try {
        HotelDetailsWrapper hwd = this.hotelEJB.getOffers(new HotelConditions(Hotel.valueOf(this.hotel.getName())));
        List<HotelOfferDetails> offers = hwd.getHotelOfferList();
        this.details = getHotelOffers(offers);

      } catch (BusinessException e) {
        BTPLogger.error(LOG, e);
      }
    }
  }

  private List<HotelOfferDTO> getHotelOffers(final List<HotelOfferDetails> offers) {
    List<HotelOfferDTO> result = new ArrayList<HotelOfferDTO>();
    for (HotelOfferDetails entry : offers) {
      HotelOfferDTO ho = new HotelOfferDTO();
      ho.setDayType(entry.getDayType().toString());
      ho.setLocation(entry.getLocation().toString());
      ho.setName(entry.getName());
      ho.setRoomType(entry.getRoomType().toString());
      ho.setPrice(entry.getPrice().getAmount());
      result.add(ho);
    }
    return result;
  }

  private double getHotelDTOPrice(final double weekdayPrice, final double weekendPrice) {
    double aux = 0;
    LocalDate day = DateUtils.convertToLocalDate(this.hotel.getStart());
    while (day.isBefore(DateUtils.convertToLocalDate(this.hotel.getEnd()))) {
      if (day.getDayOfWeek() == DayOfWeek.SATURDAY || day.getDayOfWeek() == DayOfWeek.SUNDAY) {
        aux += weekendPrice;
      } else {
        aux += weekdayPrice;
      }
      day = day.plusDays(1);
      System.out.println(day.toString());
    }
    return aux;
  }

  public List<String> getHotels() {
    List<String> result = new ArrayList<String>();
    for (Hotel h : this.hotels) {
      result.add(h.toString());
    }
    return result;
  }

  public void setHotels(final List<String> hotels) {
    List<Hotel> result = new ArrayList<Hotel>();
    for (String h : hotels) {
      result.add(Hotel.valueOf(h));
    }
    this.hotels = result;
  }

  public List<String> getLocations() {
    List<String> displayLocations = new ArrayList<String>();
    try {
      this.locations = this.hotelEJB.getAllLocations();
      for (City l : this.locations) {
        displayLocations.add(l.toString());
      }
    } catch (BusinessException e) {
      BTPLogger.error(LOG, e);
    }
    return displayLocations;
  }

  public void setLocations(final List<String> locations) {
    List<City> result = new ArrayList<City>();
    for (String loc : locations) {
      result.add(City.valueOf(loc));
    }
    this.locations = result;
  }

  public HotelDTO getHotel() {
    return this.hotel;
  }

  public void setHotel(final HotelDTO hotel) {
    this.hotel = hotel;
  }

  public List<HotelOfferDTO> getDetails() {
    return this.details;
  }

  public void setDetails(final List<HotelOfferDTO> details) {
    this.details = details;
  }

  public List<String> getRoomTypes() {
    List<String> result = new ArrayList<String>();
    for (RoomType r : this.roomTypes) {
      result.add(r.toString());
    }
    return result;
  }

  public void setRoomTypes(final List<String> roomTypes) {
    List<RoomType> result = new ArrayList<RoomType>();
    for (String r : roomTypes) {
      result.add(RoomType.valueOf(r));
    }
    this.roomTypes = result;
  }

  public double getPrice() {
    return this.price;
  }

  public void setPrice(final double price) {
    this.price = price;
  }

}
